看雪论坛作者ID:Denny Chen
最近碰到一个加壳的apk,里面有类抽取,并且有做反fart脱壳。后来经过修改fart的源码,幸运地脱壳并还原dex成功,特将脱壳经历记录于此。
此次遇到的壳中两个核心的dex文件中几乎所有的方法的codeitem都抽取了:
从hanbing大神的github上下载源码:https://github.com/hanbinglengyue/FART
fart的代码量也不大,其中一部分代码是原来系统的代码,一部分是作者自己加的代码,要想快速知道作者加了哪些代码,可以直接将fart代码文件和相应的系统源码文件(github源码中代码是对应Android 6.0系统的)双选拖到Beyond Compare中,然后作者自加的代码便一目了然(最左侧小红线的地址就是代码差异的地方)。修改和编辑系统源码的ide,考虑到只是简单的修改一些代码,这里使用了vscode,直接将系统源码根目录导入即可,然后根据vscode提示,安装一些插件也能有一些简单的代码提示和定位功能。
2
使用原始fart dump不了codeitem原因排查
一开始使用fart(fart脱壳机兼frida版fart)时,有两个dex dump下来是类被抽取了,并且codeitem没dump,显然是对fart做了防护。脱壳机中未dump出codeitem截图(frida版fart也没有,这里就不给出截图),如下:
为了排查原因和找到fart哪一步被卡住了,本人缩小排查范围,并在fart源码多个环节打印log,过程如下:1、原始的fart是对手机上所有的应用脱壳,这其中的日志不是一般的多,手机也比较卡,因此本人对脱壳的包名进行了限制,如下:
2、另外,即使在同一个应用中,上图中的代码也可能运行两次,因此加上mIsRunFartThread限制一个程序只进行一次脱壳。3、对fartwithClassloader中ClassLoader参数进行过滤。因为不是所有的dex都做了类抽取,所以仅对包含了文章开头给出的两个dex中的类(各取一个类代表即可)的ClassLoader进行排查,其它的滤掉,如下:最后排查出是fart在反射调用getClassNameList_method方法时,返回的类名列表为空。针对这个问题,本人处理的方法是将dex的类名手动导出到文件(可以通过010导出类名列表,也可直接使用fart中另一个脱壳点dumpDexFileByExecute导出的类列表,后者更快一些,但前提是得跑一次原始的fart),然后存放到sdcard中,并修改fart源码从sdcard中读取该文件,从而获取dex的所有类名列表。后面的自动调用类方法的流程没有变。虽然,目前反fart的原因找到了,但离最后脱壳还有一些距离。接下来运行过程中还碰到了一个问题:类的<clinit>方法的codeitem dump不下来。<clinit>的methodid不能通过getDeclaredConstructors和getDeclaredMethods获取到,所以原始的fart是没有对<clinit>方法进行主动调用的。后面发现Class.forName(cls)是可以触发cls中的<clinit>调用的,但是使用时,得用"Class.forName(eachclassname, true, appClassloader);",不然在fart代码调用位置默认是使用BootClassLoader,会导致类找不到。fart中还有另一个脱壳点dumpdexfilebyExecute,会将所有执行过的方法都会dump下来。至此,所有的codeitem都获取到了,然后使用hanbing大神提供的fart.py可以将codeitem和dex中反编译代码通过命令行显示出来,对fart.py进行简单修改,可以将codeitem和dex合并,获取完整dex。脱壳中过程文件和修改的脱壳机代码已加至(仅供参考):https://github.com/Chenyangming9/one-anti-fart-shell-pull
看雪ID:Denny Chen
https://bbs.pediy.com/user-home-892380.htm
*本文由看雪论坛 Denny Chen 原创,转载请注明来自看雪社区
官网:https://www.bagevent.com/event/6334937